package com.ztgf.sms.service.email;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.ztgf.sms.common.config.YmlConfig;
import com.ztgf.sms.constant.EmailConstant;
import com.ztgf.sms.mapper.sms.EmailInfoMapper;
import com.ztgf.sms.models.bo.EmailSendBO;
import com.ztgf.sms.models.dto.email.EmailInfoDTO;
import com.ztgf.sms.models.service.IEmailInfoService;
import com.ztgf.sms.models.vo.EmailVO;
import com.ztgf.user.models.service.IUserInfoService;
import com.ztgf.user.models.vo.UserInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;

import javax.annotation.Resource;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Random;

import static com.ztgf.common.utils.UtilConstants.*;

/**
 * author: chenyu.wang
 * date: 2020-05-23 17:35
 * Description:
 */
@Slf4j
@DubboService
public class EmailInfoServiceImpl extends ServiceImpl<EmailInfoMapper, EmailInfoDTO> implements IEmailInfoService {

    @Resource
    private YmlConfig ymlConfig;

    @DubboReference
    private IUserInfoService userInfoService;

    //邮件发送人的邮件地址
    private final String from = "gfmall@cresc.cn";
    //发件人的邮件帐户
    private final String username = "gfmall@cresc.cn";
    //发件人的邮件授权码
    //private final String password = "rVWDuY6crTxeXc79";
    private final String password = "fDJN8wtXxwaziW5D";
    //服务器的地址
    private final String serverUrl = "smtp.exmail.qq.com";
    //服务器的端口
    private final int serverPort = 465;
    //邮件发送地址
    @Value(value = "${email-active.url}")
    private String emailActiveUrl;
    //图片前缀地址
    @Value(value = "${email-invoice.url}")
    private String emailInvoiceUrl;

    @Override
    public void sendMail(EmailSendBO emailInfoBO) {
        String title;//邮件抬头
        String context;//邮件内容
        //定义Properties对象,设置环境信息
        Properties props = System.getProperties();
        //设置邮件服务器的地址
        props.setProperty("mail.smtp.host", serverUrl); // 指定的smtp服务器
        props.setProperty("mail.smtp.auth", "true");
        props.setProperty("mail.transport.protocol", "smtp");//设置发送邮件使用的协议
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.socketFactory.port", serverPort);
        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        //创建Session对象,session对象表示整个邮件的环境信息
        Session session = Session.getInstance(props);
        session.setDebug(true);
        //判断邮件类型设定抬头和内容
        if (emailInfoBO.getType().equals(ZERO)) {
            title = EmailConstant.EMAIL_VALIDATION_TITLE;
            context = String.format(EmailConstant.EMAIL_VALIDATION_CONTEXT, emailActiveUrl + EmailConstant.EMAIL_VALIDATION_URL + emailInfoBO.getContext());
        } else {
            title = EmailConstant.EMAIL_ACTIVITY_TITLE;
            context = emailInfoBO.getContext();
        }
        try {
            //Message的实例对象表示一封电子邮件
            MimeMessage message = new MimeMessage(session);
            //设置发件人的地址
            message.setFrom(new InternetAddress(from));
            //设置主题
            message.setSubject(title);
            //设置邮件的文本内容
            message.setContent(context, "text/html;charset=utf-8");
            //从session的环境中获取发送邮件的对象
            Transport transport = session.getTransport();
            //连接邮件服务器
            transport.connect(serverUrl, serverPort, username, password);
            //设置收件人地址,并发送消息
            transport.sendMessage(message, new Address[]{new InternetAddress(emailInfoBO.getEmail())});
            transport.close();
            this.saveEmail(emailInfoBO);
        } catch (MessagingException e) {
            log.error("发送邮件失败！", e);
        }
    }

    @Override
    public void saveCaptcha(EmailSendBO emailInfoBO) {
        String code = getCaptchaCode();
        EmailSendBO bo = new EmailSendBO();
        BeanUtils.copyProperties(emailInfoBO, bo);
        bo.setContext(code);
        sendMail(bo);
    }

    @Override
    public void sendCaptcha(EmailSendBO emailInfoBO) {
        UserInfoVO vo = userInfoService.getVo(emailInfoBO.getShopId());
        String code = getCaptchaCode();
        EmailSendBO bo = new EmailSendBO();
        BeanUtils.copyProperties(emailInfoBO, bo);
        bo.setContext(code);
        bo.setEmail(vo.getEmail());
        sendMail(bo);
    }

    @Override
    public boolean getCaptcha(EmailSendBO emailInfoBO) {
        Wrapper<EmailInfoDTO> wrapper = new EntityWrapper<>();
        wrapper.eq("email", emailInfoBO.getEmail()).eq("type", 2);
        wrapper.orderBy("create_time", false); //默认倒序

        wrapper.last("LIMIT 1"); //取第一条

        EmailInfoDTO dto = this.selectOne(wrapper);
        return verCaptcha(dto, emailInfoBO.getContext());
    }

    @Override
    public void sendActiveEail(EmailSendBO emailInfoBO) {
        emailInfoBO.setType(0);//类型 0.激活、1活动,2验证码
        String code = getCaptchaCode();
        emailInfoBO.setContext("captcha=" + code + "&userId=" + emailInfoBO.getContext());
        sendMail(emailInfoBO);

        EmailSendBO bo = new EmailSendBO();
        BeanUtils.copyProperties(emailInfoBO, bo);
        bo.setType(2);
        bo.setContext(code);
        saveEmail(bo);
    }

    /*
     * @description:后台推送邮件,店铺类型 0专营店、1专卖店、2旗舰店、3自营店
     * type:0全部用户，1全部店铺，2全部旗舰店，3全部专卖店，4全部专营店，5全部买家，6筛选
     * @author: chenyu.wang
     * @date: 2020-08-24
     */
    @Async
    @Override
    public void adminMessagePush(Integer type, String title, String context, String ids) {
        List<String> emailList = new ArrayList<>();
        if (type == ZERO) {
            //全部用户
            List<EmailVO> list = baseMapper.queryAllUserEmail();
            if (isNull(list)) {
                throw new RuntimeException("暂无用户邮箱信息!");
            }
            for (EmailVO vo : list) {
                if (StringUtils.isNotBlank(vo.getEmail())) {
                    emailList.add(vo.getEmail());
                }
            }
            this.groupSendEmail(title, context, emailList);
        } else if (type == ONE) {
            //全部店铺
            List<EmailVO> list = baseMapper.queryAllShopEmail();
            if (isNull(list)) {
                throw new RuntimeException("暂无用户邮箱信息!");
            }
            for (EmailVO vo : list) {
                if (StringUtils.isNotBlank(vo.getEmail())) {
                    emailList.add(vo.getEmail());
                }
            }
            this.groupSendEmail(title, context, emailList);
        } else if (type == TWO) {
            //全部旗舰店
            List<EmailVO> list = baseMapper.queryOtherTypeShopEmail(TWO);
            if (isNull(list)) {
                throw new RuntimeException("暂无用户邮箱信息!");
            }
            for (EmailVO vo : list) {
                if (StringUtils.isNotBlank(vo.getEmail())) {
                    emailList.add(vo.getEmail());
                }
            }
            this.groupSendEmail(title, context, emailList);
        } else if (type == THREE) {
            //全部专卖店
            List<EmailVO> list = baseMapper.queryOtherTypeShopEmail(ONE);
            if (isNull(list)) {
                throw new RuntimeException("暂无用户邮箱信息!");
            }
            for (EmailVO vo : list) {
                if (StringUtils.isNotBlank(vo.getEmail())) {
                    emailList.add(vo.getEmail());
                }
            }
            this.groupSendEmail(title, context, emailList);
        } else if (type == FOUR) {
            //全部专营店
            List<EmailVO> list = baseMapper.queryOtherTypeShopEmail(ZERO);
            if (isNull(list)) {
                throw new RuntimeException("暂无用户邮箱信息!");
            }
            for (EmailVO vo : list) {
                if (StringUtils.isNotBlank(vo.getEmail())) {
                    emailList.add(vo.getEmail());
                }
            }
            this.groupSendEmail(title, context, emailList);
        } else if (type == FIVE) {
            //全部买家
            List<EmailVO> list = baseMapper.queryAllBuyerEmail();
            if (isNull(list)) {
                throw new RuntimeException("暂无用户邮箱信息!");
            }
            for (EmailVO vo : list) {
                if (StringUtils.isNotBlank(vo.getEmail())) {
                    emailList.add(vo.getEmail());
                }
            }
            this.groupSendEmail(title, context, emailList);
        } else {
            //筛选
            List<EmailVO> list = baseMapper.queryAutoUserEmail(ids);
            if (isNull(list)) {
                throw new RuntimeException("暂无用户邮箱信息!");
            }
            for (EmailVO vo : list) {
                if (StringUtils.isNotBlank(vo.getEmail())) {
                    emailList.add(vo.getEmail());
                }
            }
            this.groupSendEmail(title, context, emailList);
        }
    }

    /*
     * @description:发送发票信息邮件
     * @author: chenyu.wang
     * @date: 2020-09-25
     * @return:
     */
    @Override
    public void sendInvoiceEmail(EmailSendBO bo) {
        String title;//邮件抬头
        String context;//邮件内容
        //定义Properties对象,设置环境信息
        Properties props = System.getProperties();
        //设置邮件服务器的地址
        props.setProperty("mail.smtp.host", serverUrl); // 指定的smtp服务器
        props.setProperty("mail.smtp.auth", "true");
        props.setProperty("mail.transport.protocol", "smtp");//设置发送邮件使用的协议
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.socketFactory.port", serverPort);
        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        //创建Session对象,session对象表示整个邮件的环境信息
        Session session = Session.getInstance(props);
        session.setDebug(true);
        title = EmailConstant.EMAIL_INVOICE_TITLE;
        context = String.format(EmailConstant.EMAIL_INVOICE_CONTEXT, emailInvoiceUrl + bo.getContext());
        try {
            //Message的实例对象表示一封电子邮件
            MimeMessage message = new MimeMessage(session);
            //设置发件人的地址
            message.setFrom(new InternetAddress(from));
            //设置主题
            message.setSubject(title);
            //设置邮件的文本内容
            message.setContent(context, "text/html;charset=utf-8");
            //从session的环境中获取发送邮件的对象
            Transport transport = session.getTransport();
            //连接邮件服务器
            transport.connect(serverUrl, serverPort, username, password);
            //设置收件人地址,并发送消息
            transport.sendMessage(message, new Address[]{new InternetAddress(bo.getEmail())});
            transport.close();
            this.saveEmail(bo);
            log.info("发送邮件成功！");
        } catch (MessagingException e) {
            e.printStackTrace();
            log.info("发送邮件失败！");
        }
    }

    @Override
    public boolean sendMailByScheduled(String title, String context, String[] emailsArr) {
        boolean flag = true;
        //定义Properties对象,设置环境信息
        Properties props = System.getProperties();
        //设置邮件服务器的地址
        props.setProperty("mail.smtp.host", serverUrl); // 指定的smtp服务器
        props.setProperty("mail.smtp.auth", "true");
        props.setProperty("mail.transport.protocol", "smtp");//设置发送邮件使用的协议
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.socketFactory.port", serverPort);
        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        //创建Session对象,session对象表示整个邮件的环境信息
        Session session = Session.getInstance(props);
        session.setDebug(true);
        try {
            //Message的实例对象表示一封电子邮件
            MimeMessage message = new MimeMessage(session);
            //设置发件人的地址
            message.setFrom(new InternetAddress(from));
            //设置主题
            message.setSubject(title);
            String alias = "";
            alias=javax.mail.internet.MimeUtility.encodeText("工服MALL");
            message.setFrom(new InternetAddress(alias + " <"+from+">"));
            //设置邮件的文本内容
            message.setContent(context, "text/html;charset=utf-8");
            //从session的环境中获取发送邮件的对象
            Transport transport = session.getTransport();
            log.info("---------------------连接邮件服务器------------------start");
            //连接邮件服务器
            transport.connect(serverUrl, serverPort, username, password);
            log.info("---------------------连接邮件服务器------------------end");
            //设置收件人地址,并发送消息
            for (String email : emailsArr) {
                InternetAddress toAddr = new InternetAddress();
                toAddr.setAddress(email);
                message.addRecipients(Message.RecipientType.BCC, toAddr.toString());
            }
//            // 密送
//            String toListms = null;
//                InternetAddress[] iaToListms = new InternetAddress()
//                        .parse(toListms);
//                message.setRecipients(Message.RecipientType.BCC, iaToListms); // 密送人
            transport.sendMessage(message, message.getAllRecipients());
            transport.close();
            log.info("发送邮件成功！");
        } catch (Exception e) {
            flag = false;
            e.printStackTrace();
            log.error(e.getMessage());
            log.info("发送邮件失败！");
        }
        return flag;
    }



    /*
     * @description:群发邮件
     * @author: chenyu.wang
     * @date: 2020-08-24
     */
    private void groupSendEmail(String title, String context, List<String> emailList) {
        //定义Properties对象,设置环境信息
        Properties props = System.getProperties();
        //设置邮件服务器的地址
        props.setProperty("mail.smtp.host", serverUrl); // 指定的smtp服务器
        props.setProperty("mail.smtp.auth", "true");
        props.setProperty("mail.transport.protocol", "smtp");//设置发送邮件使用的协议
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.socketFactory.port", serverPort);
        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        //创建Session对象,session对象表示整个邮件的环境信息
        Session session = Session.getInstance(props);
        session.setDebug(true);
        try {
            //Message的实例对象表示一封电子邮件
            MimeMessage message = new MimeMessage(session);
            //设置发件人的地址
            message.setFrom(new InternetAddress(from));
            //设置主题
            message.setSubject(title);
            //设置邮件的文本内容
            message.setContent(context, "text/html;charset=utf-8");
            //从session的环境中获取发送邮件的对象
            Transport transport = session.getTransport();
            //连接邮件服务器
            transport.connect(serverUrl, serverPort, username, password);
            //设置收件人地址,并发送消息
            for (String email : emailList) {
                InternetAddress toAddr = new InternetAddress();
                toAddr.setAddress(email);
                message.addRecipients(Message.RecipientType.TO, toAddr.toString());
            }
            transport.sendMessage(message, message.getAllRecipients());
            transport.close();
            log.info("发送邮件成功！");
        } catch (MessagingException e) {
            e.printStackTrace();
            log.info("发送邮件失败！");
        }
    }


    /**
     * description: 保存邮件日志
     * param: [emailInfoDTO]
     * author: chenyu.wang
     * date: 2020-07-06
     * return: void
     */
    @Async
    public void saveEmail(EmailSendBO emailInfoBO) {
        EmailInfoDTO dto = new EmailInfoDTO();
        if (emailInfoBO.getShopId() != null) {
            dto.setShopId(emailInfoBO.getShopId());
        }
        dto.setEmail(emailInfoBO.getEmail());
        dto.setContent(emailInfoBO.getContext());
        dto.setType(emailInfoBO.getType());
        dto.setId(ymlConfig.getPkId());
        this.insert(dto);
    }

    /**
     * 生成短信验证码并存储.
     *
     * @return String
     */
    private String getCaptchaCode() {
        StringBuilder str = new StringBuilder();
        Random random = new Random();

        for (int i = 0; i < 6; i++) {
            // 生成一个[0,10)
            int randomInt = random.nextInt(10);
            str.append(randomInt);
        }
        return str.toString();
    }

    private boolean verCaptcha(EmailInfoDTO emailInfoDTO, String captcha) {
        if (emailInfoDTO == null){
            return false;
        }

        if (!captcha.equals(emailInfoDTO.getContent())) {
            return false; //验证码不一致
        }

        Long now_m = System.currentTimeMillis(); //获取当前时间毫秒数
        Long now_s = emailInfoDTO.getCreateTime().getTime(); //获取验证码发送时间毫秒数
        Long time_out = Long.valueOf(EmailConstant.ACTIVE_TIMEOUT) * 1000; //获取验证码过期时间，秒
        Long time = now_s + time_out;
        //超时
        return time >= now_m;
    }
}
